//
//  PageSegmentViewController.swift
//  PageNavigator
//
//  Created by 张奇 on 2025/8/13.
//

import UIKit

/// SegmentItem
public protocol SegmentItemViewProtocol: UICollectionViewCell {

    ///  展示item页面
    /// - Parameters:
    ///   - associated: 绑定的数据
    func segmentItemViewDisplay(selectedIndex: Int, itemAt index: Int, associated obj: Any?)
    
    /// 不展示item页面
    /// - Parameters:
    ///   - associated: 绑定的数据
    func segmentItemViewEndDisplay(selectedIndex: Int, itemAt index: Int, associated obj: Any?)
    
    /// 视图滚动过程中调整Item
    /// - Parameter context: 滚动上下文
    func refreshScrollingSegmentItem(context: SegmentScrollingTransitionContext, itemAt index: Int, associated obj: Any?)
    
    
    /// 更新item的展示状态
    /// - Parameters:
    ///   - associated: 绑定的数据
    func refreshSegmentItemView(context: SegmentSelectedTransitionContext, itemAt index: Int, associated obj: Any?, state: UIControl.State)
}

/// Segment 指示器
public protocol SegmentIndicatorProtocol: UIView {
    
    /// 视图选中之后调整指示器
    /// - Parameter context: 选择上下文
    func refreshSelectedIndicator(context: SegmentSelectedTransitionContext)

    
    /// 视图滚动过程中调整指示器
    /// - Parameter context: 滚动上下文
    func refreshScrollingIndicator(context: SegmentScrollingTransitionContext)

}

/// Segment数据源

public protocol SegmentViewControllerDataSource: AnyObject {
        
    
    /// 获取注册的cell 类型, 必须遵守SegmentItemViewProtocol
    /// - Returns: cell的类型
    func getRegisterCellClass() -> AnyClass
    
    /// 分页有多少个数量
    /// - Parameter content: 容器
    /// - Returns: 数量
    func numberOfItems(in content: SegmentViewController) -> Int
    
    /// 容器在index位置展示的view
    /// - Parameters:
    ///   - content: 容器
    ///   - index: 位置
    /// - Returns: PageSegmentView
    
    func segmentViewController(_ content: SegmentViewController, associatedDataForItemAt index: Int) -> Any
    
    /// item 的大小
    /// - Parameter content: 容器
    /// - Returns: 数量
    func segmentViewController(_ content: SegmentViewController, sizeForItemAt index: Int) -> CGSize
    
    
    /// 获取内容大小
    /// - Parameter content: 容器
    /// - Returns: 数量
    func segmentViewController(_ content: SegmentViewController, contentSizeForItemAt index: Int) -> CGSize

}

/// Segment容器代理

public protocol SegmentViewControllerDelegate: AnyObject {
    
    /// segment 选择 index 位置
    /// - Parameters:
    ///   - content: 容器
    ///   - didSelected: 选择的位置位置
    func pageSegmentViewController(_ content: SegmentViewController, didSelected selected: Int)

}

public extension SegmentViewControllerDelegate {
    func pageSegmentViewController(_ content: SegmentViewController, didSelected selected: Int) {}
}


public class SegmentViewController: UIViewController {
    
    // 数据源
    public weak var dataSource: SegmentViewControllerDataSource?

    // 代理
    public weak var delegate: SegmentViewControllerDelegate?
    
    // item 的边界
    public var itemPadding: UIEdgeInsets = UIEdgeInsets.zero

    
    private var indicators: [SegmentIndicatorProtocol] = []
    
    private var currentPage: Int = INVAILD_PAGE_INDEX
    private var nextPage: Int = INVAILD_PAGE_INDEX

    private static let reuseId = "PageSegmentItemViewCell"
    private var collectionView: SegmentedCollectionView!
    
    private var caches: [Int: Any?] = [:]
    
    public override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        initUI()
        initData()
        doBeforeDisplay()
    }
    
    private func initData() {
       
    }
    
    private func doBeforeDisplay() {
    
    }
    
    private func initUI() {
        view.backgroundColor = UIColor.black
        let itemContentInserts = self.itemPadding
        let layout = UICollectionViewFlowLayout()
        layout.minimumLineSpacing = itemContentInserts.left + itemContentInserts.right
        layout.minimumInteritemSpacing = 0
        layout.estimatedItemSize = CGSize.init(width: 80, height: 44)
        layout.scrollDirection = UICollectionViewScrollDirection.horizontal
        layout.sectionInset = itemContentInserts
        
        guard let dataSource = self.dataSource else {
            fatalError("SegmentViewController dataSource cannot be nil")
        }
        
        let cellClazz: AnyClass = dataSource.getRegisterCellClass()
        
//        guard cellClazz.conforms(to: SegmentItemViewProtocol) else {
//            fatalError("SegmentViewController dataSource must register cell conform SegmentItemViewProtocol ")
//        }
        
        let collectionView = SegmentedCollectionView(frame: self.view.bounds, collectionViewLayout: layout)
        collectionView.register(cellClazz, forCellWithReuseIdentifier: SegmentViewController.reuseId)
        collectionView.isPagingEnabled = false
        self.view.addSubview(collectionView)
        collectionView.delegate = self
        collectionView.dataSource = self
        collectionView.backgroundColor = UIColor.white
        collectionView.allowsSelection = true
        collectionView.allowsMultipleSelection = false
        collectionView.indicators = indicators
        self.collectionView = collectionView
    }
    
    
    public override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        self.collectionView.frame = self.view.bounds
    }
    
    public override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        if (self.nextPage != self.currentPage) {
            self.select(index: self.nextPage)
        }
    }
    
    public func select(index: Int) {
        guard (self.currentPage != index) else {
            return
        }
        self.nextPage = index
        self.collectionView.selectItem(at: IndexPath(item: index, section: 0), animated: true, scrollPosition: UICollectionViewScrollPosition.centeredHorizontally)
        
        let oldIndex = self.currentPage
        guard let cell = collectionView.cellForItem(at: IndexPath.init(item: index, section: 0)) as? SegmentItemViewProtocol else {
            return
        }
        self.currentPage = index
        // 处理 segement
        let toItemFrame = cell.frame
        let toItemContentSize = {[weak self] () in
            guard let self = self else {
                return CGSize.zero
            }
            return self.dataSource?.segmentViewController(self, contentSizeForItemAt: index) ?? CGSize.zero
        }

        let context: SegmentSelectedTransitionContext

        if oldIndex != INVAILD_PAGE_INDEX,
           let old = caches[oldIndex],
           let oldCell = collectionView.cellForItem(at: IndexPath(item: oldIndex, section: 0)) as? SegmentItemViewProtocol {
            let fromItemFrame = oldCell.frame
            let fromItemContentSize = {[weak self] () in
                guard let self = self else {
                    return CGSize.zero
                }
                return self.dataSource?.segmentViewController(self, contentSizeForItemAt: oldIndex) ?? CGSize.zero
            }
            context = SegmentSelectedTransitionContext(selectedIndex: index, from: oldIndex, to: index, fromItemFrame: fromItemFrame, toItemFrame: toItemFrame, fromContentSize: fromItemContentSize, toItemContentSize: toItemContentSize)
            oldCell.refreshSegmentItemView(context: context, itemAt: oldIndex, associated: old, state: UIControl.State.normal)
        } else {
            let fromItemFrame = CGRect.zero
            let fromItemContentSize = { CGSize.zero }
            context = SegmentSelectedTransitionContext(selectedIndex: index, from: oldIndex, to: index, fromItemFrame: fromItemFrame, toItemFrame: toItemFrame, fromContentSize: fromItemContentSize, toItemContentSize: toItemContentSize)
        }

        cell.refreshSegmentItemView(context: context, itemAt: index, associated: caches[index] ?? nil, state: UIControl.State.selected)

        self.delegate?.pageSegmentViewController(self, didSelected: index)
        // 处理 指示器
        indicators.forEach { indicator in
            indicator.refreshSelectedIndicator(context: context)
        }
    }
    
    public func addIndicator(_ indicator: SegmentIndicatorProtocol) {
        indicators.append(indicator)
        guard let collectionView = self.collectionView else {
            return
        }
        collectionView.addIndicator(indicator)

    }
    
   public func scrolling(from: Int, to: Int, percent: CGFloat) {
       guard let toCell = collectionView.cellForItem(at: IndexPath.init(item: to, section: 0)) as? SegmentItemViewProtocol,
             let fromCell = collectionView.cellForItem(at: IndexPath.init(item: from, section: 0)) as? SegmentItemViewProtocol else {
           return
       }
       
       // 处理 segement
       let toItemFrame = toCell.frame
       let toItemContentSize = {[weak self] () in
           guard let self = self else {
               return CGSize.zero
           }
           return self.dataSource?.segmentViewController(self, contentSizeForItemAt: to) ?? CGSize.zero
       }
       
       let fromItemFrame = fromCell.frame
       let fromItemContentSize = {[weak self] () in
           guard let self = self else {
               return CGSize.zero
           }
           return self.dataSource?.segmentViewController(self, contentSizeForItemAt: from) ?? CGSize.zero
       }
       
       let context = SegmentScrollingTransitionContext(selectedIndex: self.currentPage, from: from, to: to, percent: percent, fromItemFrame: fromItemFrame, toItemFrame: toItemFrame, fromContentSize: fromItemContentSize, toItemContentSize: toItemContentSize)
       
       fromCell.refreshScrollingSegmentItem(context: context, itemAt: from, associated: caches[from] ?? nil)
       
       toCell.refreshScrollingSegmentItem(context: context, itemAt: to, associated: caches[to] ?? nil)
       
       // 处理 指示器
       indicators.forEach { indicator in
           indicator.refreshScrollingIndicator(context: context)
       }
    }
    
    public override func didMove(toParentViewController parent: UIViewController?) {
        super.didMove(toParentViewController: parent)
    }

    public override func willMove(toParentViewController parent: UIViewController?) {
        super.willMove(toParentViewController: parent)
    }

}


extension SegmentViewController: UICollectionViewDataSource {
    
    public func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1;
    }
    
    public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.dataSource?.numberOfItems(in: self) ?? 0
    }
    
    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let index = indexPath.item
        
        caches[index] = dataSource?.segmentViewController(self, associatedDataForItemAt: index)
        return collectionView.dequeueReusableCell(withReuseIdentifier: SegmentViewController.reuseId,
                                                  for: indexPath)
    }
}


extension SegmentViewController: UICollectionViewDelegateFlowLayout {
    
    public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return self.dataSource?.segmentViewController(self, sizeForItemAt: indexPath.item) ?? CGSize.zero
    }
    
    public func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        guard let cell = cell as? SegmentItemViewProtocol, let will = caches[indexPath.item] else {
            return
        }
        
        cell.segmentItemViewDisplay(selectedIndex: self.currentPage, itemAt: indexPath.item, associated: will)
    }
    
    public func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        guard let cell = cell as? SegmentItemViewProtocol, let end = caches[indexPath.item] else {
            return
        }
        
        cell.segmentItemViewEndDisplay(selectedIndex: self.currentPage, itemAt: indexPath.item, associated: end)
    }
    
    public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        collectionView.deselectItem(at: indexPath, animated: false)
        guard indexPath.item != self.currentPage else {
            return
        }
        self.currentPage = indexPath.item
        self.nextPage = indexPath.item
        self.delegate?.pageSegmentViewController(self, didSelected: indexPath.item)
        
    }
}

